#pragma once

#include <Windows.h>
#include <list>

extern HINSTANCE g_hInstance;

//basic window & layout system
class CWindow {
public:
	CWindow();
	CWindow(HWND hWnd);
	virtual ~CWindow();

	HWND GetHWND();
	const HWND GetHWND() const;

	int SetHWND(HWND hWnd);

private:
	HWND m_hWnd;
};

CWindow* GetCWindow(HWND hWnd);



//basic layout system
enum EAppendDir {
	APPEND_UP,
	APPEND_DOWN,
	APPEND_LEFT,
	APPEND_RIGHT
};

enum EPosType {
	POSITION_PIXEL,
	POSITION_RATIO
};



class CLayout {
private:
	struct SLayoutItem;

public:
	struct SPosValue {
		EPosType postype;
		
		union {
			int pixel;
			float ratio;
		} value;
	};

	typedef std::list<SLayoutItem>::iterator HLAYOUTITEM;
	  // NOTE : VS2012's STL list semms to implement std::list<T> using
	  // pointer to T only, so that the full definition of SLayoutObject
	  // is not needed. I'm not yet certain if this is standard. So this
	  // def may change. Even if you change the above def, make sure that
	  // users can use the same interface as the original version.

	CLayout();
	virtual ~CLayout();

	void SetApplyTarget(CWindow* target);
	void SetRect(RECT rt);

	void Clear();

	static SPosValue CreatePixelPosValue(int pixel);
	static SPosValue CreateRatioPosValue(float ratio);

	HLAYOUTITEM CreateItem();
	HLAYOUTITEM SetWindow(HLAYOUTITEM orig, EAppendDir dir, CWindow* subwindow, SPosValue size, int margin);
		// Append child window to layout so that their position is managed by layout system.
	HLAYOUTITEM SetLayout(HLAYOUTITEM orig, EAppendDir dir, CLayout* sublayout, SPosValue size, int margin);
		// Append sublayout : used for table/grid manipulation, maybe?
	HLAYOUTITEM SetGrid(HLAYOUTITEM orig, EAppendDir dir, CWindow** subWindows, int nHorizontal, int nVertical,
		SPosValue size, int margin, int submargin);	// create equally-spaced grid for windows.
																// custom grids should be made with AppendWindows.
																// See source of AppendGrid for more info.

	// size argument in AppendXXX :
	//  when dir == APPEND_TOP or APPEND_BOTTOM -> Appended window's width in working rect = 100%, height = size
	//	when dir == APPEND_LEFT or APPEND_RIGHT -> inverted
	
	void GetLayoutItemPos(HLAYOUTITEM item, EAppendDir   *dir, SPosValue   *size, int   *margin) const;
	void SetLayoutItemPos(HLAYOUTITEM item, EAppendDir newdir, SPosValue newsize, int newmargin);

	void DeleteLayoutItem(HLAYOUTITEM item);
	
	bool IsResizable(int w, int h) const;
	void GetMinimumSize(int *w, int *h) const;
	void UpdatePos();
	
private:
	HWND GetTargetHWND();

	enum EItemType {
		ITEM_WINDOW,
		ITEM_LAYOUT
	};


	struct SLayoutItem {
		EAppendDir m_Dir;
		EItemType m_ItemType;
		union {
			CWindow* m_Wnd;
			CLayout* m_Layout;
		} m_Data;
		SPosValue m_Size;
		int m_Margin;
	};

	CWindow* m_TargetWindow;
	RECT m_Rect;

	std::list<SLayoutItem> m_WindowTable;
};

typedef CLayout::HLAYOUTITEM HLAYOUTITEM;